package com.cellulam.framework.test.conf;

import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.List;

public abstract class MethodCostAspect {

    private static final Logger logger = LoggerFactory.getLogger(MethodCostAspect.class);

    public static List<MethodCost> METHOD_COST = Lists.newCopyOnWriteArrayList();

    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        String method = this.getMethodName(pjp);
        logger.info("start invoke method: {}", method);
        long start = System.currentTimeMillis();
        try {
            return pjp.proceed();
        } catch (Throwable e) {
            throw e;
        } finally {
            long cost = System.currentTimeMillis() - start;
            if(cost > 50) {
                METHOD_COST.add(new MethodCost(method, cost, 1));
                logger.info("end invoke method: {}, method cost: {} ms", method, cost);
            }
        }
    }

    protected String getMethodName(ProceedingJoinPoint pjp) {
        return pjp.getTarget().getClass().getName() + "." + this.getMethod(pjp).getName();
    }

    protected Method getMethod(ProceedingJoinPoint pjp) {
        MethodSignature signature = ((MethodSignature) pjp.getSignature());
        return signature.getMethod();
    }

    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class MethodCost {
        private String name;

        private long cost;

        private int count;

        @Override
        public String toString() {
            return String.format("[%s] cost: %s, count: %s", name, cost, count);
        }
    }
}
